<?php
/** 
 * 
 *
 * @package api
 * @subpackage lib
 * @author Richard Fullmer <php-api@byu.edu>
 * 
 * @version 1.0
 */


/**
 * @package api
 * @subpackage lib
 */
class api_SSO {
	private $site_config; 
	private $sid;
	private $auth;
	
	

	public function __construct( $new_config = null ) {
		if ($new_config == null) {
			$this->site_config = array(
				// automatic authentication and session checking
				'auto'            => '1',
			
				// authentication configuration
				'sso_service'     => '',
				'sso_password'    => '',
				'logout_page'     => 'logout.php',
				'logout_redirect' => '1',
			
				// session configuration
				'sess_enable'     => '1',
				'sess_cookie'     => 'sso',
				'sess_path'       => '/',
				'sess_host'       => 'byu.edu',
				'sess_length'     => '3600',
				'sess_secure'     => '0',
			
				// the remaining parameters are required to store sessions in a databsase 
				// if not specified, sessions will be store on the local file system
				//'db_host'         => 'db.cws.oregonstate.edu',
				//'db_username'     => '',
				//'db_password'     => '',
				//'db_name'         => '',
				//'db_table'        => 'session',		// name of session table
				//'db_sid_col'      => 'sid',			// expected type: varchar(32)
				//'db_expire_col'   => 'expire',		// expected type: unsigned int
				//'db_data_col'     => 'data',		// expected type: text
			
				// you should not need to change these
				//'sso_host'        => 'secure.onid.oregonstate.edu',
				//'sso_path'        => '/cgi-bin/sso.pl',
				//'sso_cookie'      => 'sso',
				//'sso_login_url'   => 'https://secure.onid.oregonstate.edu/login',
			);
		}
		else {
			$this->site_config = $new_config;
		}
	}

	public function config() {
		return $this->site_config;
	}
	
	/**
	 *  Start or continue a local session 
	 *
	 *  @return string local session id on success
	 */
	function session_check()
	{
		if ( isset($this->sid) ) {
			return $this->sid;
		}
	
		// if we get here, we haven't started sessions yet...
		$conf = $this->config();
		if ($conf['sess_enable'] && $conf['sess_cookie']) {
			// session/cookie name
			$c_name = $conf['sess_cookie'];
	
			// using the sso cookie for our session id
			
			$c_host = !empty($conf['sess_host']) ? $conf['sess_host'] : $_SERVER['HTTP_HOST'];
			$c_path = !empty($conf['sess_path']) ? $conf['sess_path'] : '/';
			$c_secure = !empty($conf['sess_secure']) ? $conf['sess_secure'] : 0;
			$c_length = !empty($conf['sess_length']) ? $conf['sess_length'] : 0;
			
	
			// we're using cookie based sessions here...
			session_set_cookie_params($c_length, $c_path, $c_host, $c_secure);
	
			// specify session name
			session_name($c_name);
	
			// make sure we continue using any existing session id
			if (isset($_COOKIE[$c_name])) {
				session_id($_COOKIE[$c_name]);
			}
	
			// fire up the session
			session_start();
	
			// need to reset session if a new sso login is detected
			if ((!empty($_SESSION['sso']['sid'])) && ($_SESSION['sso']['sid'] != $_COOKIE[$conf['sso_cookie']])) {
	
				// session_regenerate_id() doesn't function as documented with custom session handlers
				// so we must explicitly destroy and start a new session.
				session_regenerate_id();
				$new_sid = session_id();
	
				$_SESSION = array();
				session_destroy();
		
				// set new sid and start the new session
				session_id($new_sid);
				session_start();
			}
	
			// remember session id for future calls to this function
			$this->sid = session_id();
			$_COOKIE[$c_name] = $this->sid;
	
		// sessions not enabled
		} else {
			$this->sid = '';
		}
	
		return $this->sid;
	}
	
	/**
	 *  Destroy local session data
	 *
	 *  @return bool true
	 */
	public function session_destroy()
	{
		$conf = sso_config();
		if ($sid = $this->session_check()) {
			// unset all session vars
			$_SESSION = array();
	
			// delete session cookie only if not sharing the sso cookie
			// (this shared cookie gets deleted by sso_logout())
			if (isset($_COOKIE[$conf['sess_cookie']]) && ($conf['sess_cookie'] !== $conf['sso_cookie'])) {
				// session/cookie name
				$c_name = $conf['sess_cookie'];
				$c_host = !empty($conf['sess_host']) ? $conf['sess_host'] : $_SERVER['HTTP_HOST'];
				$c_path = !empty($conf['sess_path']) ? $conf['sess_path'] : '/';
				$c_secure = !empty($conf['sess_secure']) ? $conf['sess_secure'] : 0;
				setcookie($c_name, '', time() - 3600, $c_path, $c_host, $c_secure);
				unset($_COOKIE[$c_name]);
			}
	
			// destroy session
			session_destroy();
	
			// need to set handlers again (see bug http://bugs.php.net/bug.php?id=32330)
			if (sso_db_connect()) {
				session_set_save_handler(
					"sso_sess_open",
					"sso_sess_close",
					"sso_sess_read",
					"sso_sess_write",
					"sso_sess_destroy",
					"sso_sess_gc");
			}
		}
		return true;
	}

	/**
	 * Authenticate the current sso session
	 *
	 * @param bool $redirect redirect to sso login page (default = true)
	 * @param bool $extend extend sso login expiration (default = true)
	 * @param mixed $query hash of values to append to login query string or null
	 * @return mixed int expire time on success, 0 on failure
	 */
	public function authenticate($redirect = true, $extend = true, $query = null)
	{
		if (isset($this->auth)) {
			if (!$this->auth && $redirect) {
				$this->login($query);
			}
			return $this->auth;
		}
	
		$conf = $this->config();
	
		// return if authentication is not configured
		if (empty($conf['sso_service']) || empty($conf['sso_password'])) {
			return 0;
		}
	
		if ($conf['sso_cookie'] && !empty($_COOKIE[$conf['sso_cookie']])) {
			$sid = $_COOKIE[$conf['sso_cookie']];
			$ssoauth = $conf['sso_service'] . ":" . $conf['sso_password'];
	
			$message = new XML_RPC_Message('sso.session_check',
						array(new XML_RPC_Value($ssoauth, 'string'),
							new XML_RPC_Value($sid, 'string'),
							new XML_RPC_Value($extend ? 1 : 0, 'int')));
	
			$server = new XML_RPC_Client($conf['sso_path'], "https://$conf[sso_host]");
			$result = $server->send($message, 0);
	
			if (is_object($result) && ($result->faultCode() === 0)) {
				$array = XML_RPC_decode($result->value());
				if (strcmp($array['valid'], 1) === 0) {
					$auth = $array['expire_time'];
					return $auth;
				}
			}
		}
	
		// if we get here, they are invalid - send them to the login page or return false
		$auth = 0;
		if ($redirect) {
			$this->login($query);
		}
		return $auth;
	}

	

	public function get_session_name() {
		return session_name();
	}
	
	public function get_session() {
		return $_SESSION;
	}

}

?>